package com.hollysys.usersync.service.impl;

import com.hollysys.usersync.entity.Response;
import com.hollysys.usersync.entity.SyncResult;
import com.hollysys.usersync.entity.platform.Post;
import com.hollysys.usersync.entity.platform.RelUser;
import com.hollysys.usersync.feign.AuthServiceInvoker;
import com.hollysys.usersync.interceptor.AppToken;
import com.hollysys.usersync.service.SyncOrgService;
import com.hollysys.usersync.service.SyncPostService;
import com.hollysys.usersync.utils.ExecuteUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 岗位信息同步服务 - 实现类
 */
@Service
@Log4j2
public class SyncPostServiceImpl implements SyncPostService {

    @Resource
    private AuthServiceInvoker authService;

    @Resource
    private SyncOrgService syncOrgService;

    /**
     * 线程池
     */
    private final ExecutorService executorService = new ScheduledThreadPoolExecutor(10,
            new BasicThreadFactory.Builder().namingPattern("sync-schedule-pool-%d").daemon(true).build());


    /**
     * 获得岗位信息字典
     *
     * @param key    字典键
     * @param value  字典值
     * @param filter 过滤条件
     * @return 岗位信息字典
     */
    @Override
    public <R, V> Map<R, V> getPostMap(@NotNull Function<Post, R> key, @NotNull Function<Post, V> value,
                                       @Nullable Predicate<Post> filter) {
        // 获取岗位全量列表
        Response<List<Post>> postListResponse = authService.getPostList(AppToken.getToken());
        if (postListResponse.getStatus() != 0) {
            log.error("岗位列表查询失败" + postListResponse.getMessage());
            return new HashMap<>(0);
        }
        // 筛选分类
        filter = Objects.isNull(filter) ? u -> true : filter;
        return postListResponse.getData().parallelStream()
                .filter(filter)
                .collect(Collectors.toMap(key, value));
    }


    /**
     * 新增岗位
     *
     * @param postList 岗位实体列表
     * @return 操作结果
     */
    @Override
    public List<SyncResult> addPost(List<Post> postList) {
        // 第三方提供OrganizationId实际为组织编号（Code），平台对岗位的操作为岗位ID，因此需要先转换
        // 将关联组织Code转换为Id
        List<String> orgCode = postList.parallelStream().map(Post::getOrganizationId).filter(Objects::nonNull).collect(Collectors.toList());
        Map<String, String> orgCodeIdMap = syncOrgService.convertOrgCode2Id(orgCode);
        // 新增岗位
        List<ExecuteUtil.AsyncResult<Post, Response<String>>> resultList = ExecuteUtil.batchAsyncCall(postList, executorService,
                (post) -> {
                    String orgId = Optional.ofNullable(orgCodeIdMap.get(post.getOrganizationId()))
                            .orElseThrow(() -> new RuntimeException("组织编号不存在"));
                    post.setOrganizationId(orgId);
                    return authService.addPost(post, AppToken.getToken());
                });
        return resultList.stream().map(result -> SyncResult.builder()
                .status(result.getResult() && result.getValue().getStatus() == 0)
                .code(result.getRawParam().getCode())
                .message(result.getResult() ? result.getValue().getMessage() : result.getExceptionMessage())
                .build()
        ).collect(Collectors.toList());
    }

    /**
     * 修改岗位信息
     *
     * @param postList 岗位实体列表
     * @return 成功修改的条数
     */
    @Override
    public List<SyncResult> updatePost(List<Post> postList) {
        // 第三方提供OrganizationId实际为组织编号（Code），平台对岗位的操作为岗位ID，因此需要先转换
        // 将关联组织Code转换为Id,将岗位code对应ID查询并回填
        List<String> orgCodes = new ArrayList<>();
        List<String> postCodes = new ArrayList<>();
        postList.parallelStream().forEach(post -> {
            orgCodes.add(post.getOrganizationId());
            postCodes.add(post.getCode());
        });
        Map<String, String> orgCodeIdMap = syncOrgService.convertOrgCode2Id(orgCodes);
        Map<String, String> postCodeIdMap = this.convertPostCode2Id(postCodes);
        // 修改岗位
        List<ExecuteUtil.AsyncResult<Post, Response<String>>> resultList = ExecuteUtil.batchAsyncCall(postList, executorService,
                (post) -> {
                    String orgId = Optional.ofNullable(orgCodeIdMap.get(post.getOrganizationId()))
                            .orElseThrow(() -> new RuntimeException("组织编号不存在"));
                    post.setOrganizationId(orgId);
                    post.setId(postCodeIdMap.get(post.getCode()));
                    return authService.updatePost(post, AppToken.getToken());
                });
        // 更新岗位
        return resultList.stream().map(result -> SyncResult.builder()
                .status(result.getResult() && result.getValue().getStatus() == 0)
                .code(result.getRawParam().getCode())
                .message(result.getResult() ? result.getValue().getMessage() : result.getExceptionMessage())
                .build()
        ).collect(Collectors.toList());
    }

    /**
     * 删除指定岗位信息
     *
     * @param postList 岗位实体列表
     * @return 成功删除的条数
     */
    @Override
    public List<SyncResult> deletePost(List<Post> postList) {
        List<String> postCodes = postList.stream().map(Post::getCode).collect(Collectors.toList());
        Map<String, String> postMap = this.getPostMap(Post::getId, Post::getCode, post -> postCodes.contains(post.getCode()));

        List<ExecuteUtil.AsyncResult<String, Response<String>>> resultList = ExecuteUtil.batchAsyncCall(
                new ArrayList<>(postMap.keySet()), executorService,
                (postId) -> {
                    authService.addPostUser(RelUser.builder().id(postId).users(new ArrayList<>(0)).build(), AppToken.getToken());
                    return authService.deletePost(postId, AppToken.getToken());
                });

        return resultList.stream().map(result -> SyncResult.builder()
                .status(result.getResult() && result.getValue().getStatus() == 0)
                .code(postMap.get(result.getRawParam()))
                .message(result.getResult() ? result.getValue().getMessage() : result.getExceptionMessage())
                .build()
        ).collect(Collectors.toList());
    }


    /**
     * 将岗位code转换为id
     *
     * @param codeList 岗位code列表
     * @return 岗位ID列表
     */
    @Override
    public Map<String, String> convertPostCode2Id(List<String> codeList) {
        if (ObjectUtils.isEmpty(codeList)) {
            return new HashMap<>(0);
        }
        // 获取岗位全量列表
        Response<List<Post>> postListResponse = authService.getPostList(AppToken.getToken());
        if (postListResponse.getStatus() != 0) {
            log.error("岗位列表查询失败" + postListResponse.getMessage());
            return new HashMap<>(0);
        }
        // 将code转换为id
        return postListResponse.getData().parallelStream()
                .filter(post -> codeList.contains(post.getCode()))
                .collect(Collectors.toMap(Post::getCode, Post::getId));
    }

}
